#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/fb.h>

#include "screen.h"

#define SCREEN_SIZE ((LCD_SIZE_WIDTH * LCD_SIZE_HEIGHT) / 8)
static int fbfd = -1;
static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;
static char *fbp = NULL;
static int screensize = 0;

// 屏幕缓冲区，保存128x64的像素数据
static unsigned char screen_buffer[SCREEN_SIZE];

void SCREEN_SetPixel(int iPosX, int iPosY, int iColor)
{
   // printf("SetPixel(%d, %d, %d)\n", iPosX, iPosY, iColor);
    // 边界检查
    if (iPosX < 0 || iPosX >= LCD_SIZE_WIDTH || 
        iPosY < 0 || iPosY >= LCD_SIZE_HEIGHT) {
        return;
    }
    
    // 计算在缓冲区中的位置和位
    int pos = iPosY * 16 + iPosX/8;
    int bit = iPosX % 8;
    
    if (iColor) {
        // 设置对应位（置1）
        screen_buffer[pos] |= (1 << bit);
    } else {
        // 清除对应位（置0）
        screen_buffer[pos] &= ~(1 << bit);
    }
}

int SCREEN_GetPixel(int iPosX, int iPosY)
{
    // 边界检查
    if (iPosX < 0 || iPosX >= LCD_SIZE_WIDTH || 
        iPosY < 0 || iPosY >= LCD_SIZE_HEIGHT) {
        return SCREEN_COLOR_BKG;
    }
    
    // 计算在缓冲区中的位置
    int pos = iPosY * (LCD_SIZE_WIDTH/8) + iPosX/8;
    int bit = iPosX % 8;
    
    // 检查对应位是否被设置
    if (screen_buffer[pos] & (1 << bit)) {
        return SCREEN_COLOR_FRG;
    } else {
        return SCREEN_COLOR_BKG;
    }
}

void test_SCREEN_SetPixel();
int SCREEN_Initialize(void)
{
    // 打开framebuffer设备
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd < 0) {
        perror("Error: cannot open framebuffer device");
        return -1;
    }
    
    // 获取屏幕固定信息
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        perror("Error reading fixed information");
        close(fbfd);
        return -1;
    }
    
    // 获取屏幕可变信息
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        perror("Error reading variable information");
        close(fbfd);
        return -1;
    }
    vinfo.xres = 128;
    vinfo.bits_per_pixel = 1;
    vinfo.xres_virtual = 128;
    
    // 计算屏幕缓冲区大小
    screensize = finfo.smem_len;
    
    // 映射framebuffer到内存
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if ((int)(long)fbp == -1) {
        perror("Error: failed to map framebuffer device to memory");
        close(fbfd);
        return -1;
    }
    
    // 初始化屏幕缓冲区
    memset(fbp, 0, 128 * 20);
   // SCREEN_ClearDisplay();
   // SCREEN_RefreshScreen();
     vinfo.yoffset = 0;  
    if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) < 0) {
        perror("Failed to pan display");
    } else {
      //  printf("Display refreshed using FBIOPAN_DISPLAY\n");
   //   save_raw_framebuffer_data(fbp, "/mnt/sd/sreen/raw1_frames.dat");
    }

      
    SCREEN_ClearDisplay();
    SCREEN_RefreshScreen();
    

 //   test_SCREEN_SetPixel();
    return 0;
}

void SCREEN_ClearDisplay(void)
{
    // 清空内部缓冲区
    memset(screen_buffer, 0x0, sizeof(screen_buffer));
    
    // 如果framebuffer已初始化，也清空它
    if (fbp != NULL) {
        memset(fbp, 0x0, screensize);
    }
}

void SCREEN_RefreshScreen(void)
{
    if (fbp == NULL) return;
    
     memcpy(fbp, screen_buffer, SCREEN_SIZE);
     vinfo.yoffset = 0;  
    if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) < 0) {
        perror("Failed to pan display");
    } else {
      //  printf("Display refreshed using FBIOPAN_DISPLAY\n");
   //   save_raw_framebuffer_data(fbp, "/mnt/sd/sreen/raw1_frames.dat");
    }
    
}


// 测试函数
void test_SCREEN_SetPixel() {
    printf("Testing SCREEN_SetPixel function...\n");
    
    // 初始化显示
    SCREEN_ClearDisplay();
    
    // 测试1: 设置几个像素点为前景色
    SCREEN_SetPixel(0, 0, SCREEN_COLOR_FRG);    // 设置(0,0)点
    SCREEN_SetPixel(10, 10, SCREEN_COLOR_FRG);  // 设置(10,10)点
    SCREEN_SetPixel(50, 30, SCREEN_COLOR_FRG);  // 设置(50,30)点
    SCREEN_SetPixel(127, 63, SCREEN_COLOR_FRG); // 设置右下角点(127,63)
    
    // 测试2: 设置几个像素点为背景色
    SCREEN_SetPixel(0, 0, SCREEN_COLOR_BKG);    // 将(0,0)点设为背景色
    SCREEN_SetPixel(20, 20, SCREEN_COLOR_BKG);  // 设置(20,20)点为背景色
    
    // 测试3: 边界测试
    SCREEN_SetPixel(-1, 10, SCREEN_COLOR_FRG);   // 超出左边界，应被忽略
    SCREEN_SetPixel(128, 10, SCREEN_COLOR_FRG);  // 超出右边界，应被忽略
    SCREEN_SetPixel(10, -1, SCREEN_COLOR_FRG);   // 超出上边界，应被忽略
    SCREEN_SetPixel(10, 64, SCREEN_COLOR_FRG);   // 超出下边界，应被忽略
    
    // 测试4: 绘制简单图形
    // 绘制一条对角线
    for(int i = 0; i < 64 && i < LCD_SIZE_WIDTH; i++) {
        SCREEN_SetPixel(i, i, SCREEN_COLOR_FRG);
    }
    
    // 刷新显示以查看结果
    SCREEN_RefreshScreen();
    getchar();
    printf("SCREEN_SetPixel testing completed.\n");
}